package com.gupao.mvcframework.v1.servlet;

import com.gupao.mvcframework.annotation.GPAutowired;
import com.gupao.mvcframework.annotation.GPController;
import com.gupao.mvcframework.annotation.GPRequestMapping;
import com.gupao.mvcframework.annotation.GPService;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

public class GPDispatcherServlet extends HttpServlet {
    private Map<String, Object> mapping = new HashMap<String, Object>();

    @Override
    public void init(ServletConfig config) throws ServletException {
        System.out.println("GPDispatcherServlet-----------------start");
        InputStream is = null;
        try {
            System.out.println(config.getInitParameter("contextConfigLocation"));
            //获取配置文件流
            is = this.getClass().getClassLoader().getResourceAsStream(config.getInitParameter("contextConfigLocation"));
            Properties contextConfig = new Properties();
            contextConfig.load(is);
            //获取properties中配置的扫描路径
            String scanPackage = contextConfig.getProperty("scanPackage");
            //扫描文件，将路径存放在mapping中
            doScanner(scanPackage);
            for(String className : mapping.keySet()){
                if(!className.contains(".")){
                    continue;
                }
                Class<?> clazz = Class.forName(className);
                if(clazz.isAnnotationPresent(GPController.class)){
                    mapping.put(className, clazz.newInstance());
                    String baseUrl = "";
                    if(clazz.isAnnotationPresent(GPRequestMapping.class)){
                        GPRequestMapping gpRequestMapping = clazz.getAnnotation(GPRequestMapping.class);
                        baseUrl = gpRequestMapping.value();
                    }
                    Method[] methods = clazz.getMethods();
                    for(Method method : methods){
                        if(!method.isAnnotationPresent(GPRequestMapping.class)){
                            continue;
                        }
                        GPRequestMapping gpRequestMapping = method.getAnnotation(GPRequestMapping.class);
                        String url = (baseUrl + "/" + gpRequestMapping.value()).replaceAll("/+","/");
                        //将注解上的value和method关联起来
                        mapping.put(url, method);
                    }
                }else if(clazz.isAnnotationPresent(GPService.class)){
                    GPService gpService = clazz.getAnnotation(GPService.class);
                    String beanName = gpService.value();
                    Object instance = clazz.newInstance();
                    if("".equals(beanName)){
                        beanName = clazz.getName();
                    }
                    //将注解上的value值和实例关联起来
                    mapping.put(beanName, instance);
                    //将其接口与实例关联起来
                    for(Class<?> i : clazz.getInterfaces()){
                        mapping.put(i.getName(), instance);
                    }
                }else{
                    continue;
                }
            }
            //依赖注入
            for(Object object : mapping.values()){
                if(object == null){
                    continue;
                }
                Class<?> clazz = object.getClass();
                if(clazz.isAnnotationPresent(GPController.class)){
                    Field[] fields = clazz.getFields();
                    for(Field field : fields){
                        if(!field.isAnnotationPresent(GPAutowired.class)){
                            continue;
                        }
                        GPAutowired gpAutowired = field.getAnnotation(GPAutowired.class);
                        String beanName = gpAutowired.value();
                        if("".equals(beanName)){
                            beanName = field.getType().getName();
                        }
                        field.setAccessible(true);
                        field.set(mapping.get(clazz.getName()), mapping.get(beanName));
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if(is != null){
                try {is.close();} catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        System.out.println("GPDispatcherServlet-----------------end");

    }

    private void doScanner(String scanPackage) {
        URL url = this.getClass().getClassLoader().getResource("/" + scanPackage.replaceAll("\\.","/"));
        File classDir = new File(url.getFile());
        for(File file : classDir.listFiles()){
            //如果是文件夹就递归操作
            if(file.isDirectory()){
                doScanner(scanPackage + "." + file.getName());
            }else{
                if(!file.getName().endsWith(".class")){
                    continue;
                }
                String clazzName = scanPackage + "." + file.getName().replace(".class", "");
                mapping.put(clazzName, null);
            }
        }

    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        try {
            doDispatch(req, resp);
            
        } catch (Exception e) {
            resp.getWriter().write("500 " + Arrays.toString(e.getStackTrace()));
        }
    }

    private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws Exception {
        String uri = req.getRequestURI();
        StringBuffer url = req.getRequestURL();
        String contextPath = req.getContextPath();
        Map<String, String[]> params = req.getParameterMap();
        for(Object obj : this.mapping.entrySet()){
            System.out.println(obj);
        }
        System.out.println("请求中--------------------");
        System.out.println(uri);//输出"/spring/demo"
        System.out.println(url);//输出"http://localhost:8082/spring/demo"
        System.out.println(contextPath);//输出项目名称"/spring"
        System.out.println(params);
        //替换项目名和多余个斜杠
        uri = uri.replace(contextPath, "").replaceAll("/+", "/");
        //如果初始化里没有uri，则提示404
        if(!this.mapping.containsKey(uri)){
            resp.getWriter().write("404 Not Found ");
        }
        Method method = (Method) this.mapping.get(uri);
        method.invoke(this.mapping.get(method.getDeclaringClass().getName()), new Object[]{req, resp, params.get("name")[0]});
    }

}
